#include <Windows.h>
#include <strsafe.h>
#include <gdiplus.h>

// #pragma execution_character_set("gbk")

void DrawCell(HDC &hdc, const RECT &rcTarget, const HBRUSH &hbrUpper, const HBRUSH &hbrLower)
{

    HRGN hRgnUpper = CreateRoundRectRgn(rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom, 42, 38);
    HRGN hRgnLower = CreateRoundRectRgn(rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom, 42, 38);

    HRGN hRgnCutFromUpper = CreateRectRgn(rcTarget.left, rcTarget.top + ((rcTarget.bottom - rcTarget.top) / 2), rcTarget.right, rcTarget.bottom);
    HRGN hRgnCutFromLower = CreateRectRgn(rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom - ((rcTarget.bottom - rcTarget.top) / 2));

    CombineRgn(hRgnUpper, hRgnUpper, hRgnCutFromUpper, RGN_DIFF);
    CombineRgn(hRgnLower, hRgnLower, hRgnCutFromLower, RGN_DIFF);

    FillRgn(hdc, hRgnUpper, hbrUpper);
    FillRgn(hdc, hRgnLower, hbrLower);

    DeleteObject(hRgnCutFromLower);
    DeleteObject(hRgnCutFromUpper);
    DeleteObject(hRgnLower);
    DeleteObject(hRgnUpper);
}
void DrawRoundRectRgn(HDC hdc)
{
    RECT rcTarget;
    rcTarget.left = 1500;
    rcTarget.top = 20;
    rcTarget.right = 1775;
    rcTarget.bottom = 188;

    HBRUSH hRed = CreateSolidBrush(RGB(255, 0, 0));
    HBRUSH hGreen = CreateSolidBrush(RGB(0, 255, 0));

    DrawCell(hdc, rcTarget, hRed, hGreen);
}
VOID DrawLine(HDC hdc)
{
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
    Gdiplus::Pen pen(Gdiplus::Color(255, 0, 255, 0), 10);
    Gdiplus::REAL dashValues[4] = {5, 2, 15, 4};
    pen.SetDashPattern(dashValues, 4);
    pen.SetLineCap(Gdiplus::LineCap::LineCapRound, Gdiplus::LineCap::LineCapRound, Gdiplus::DashCap::DashCapRound);
    graphics.DrawLine(&pen, 10, 10, 310, 310);
}
void DrawLineMouse(HWND hWnd, LPARAM lParam)
{
    HDC hdc = GetDC(hWnd);
    //换颜色
    HPEN hPen = CreatePen(PS_SOLID, 5, RGB(255, 0, 255));
    HPEN holdPen = (HPEN)SelectObject(hdc, hPen);
    //画线
    int xPos = LOWORD(lParam);
    int yPos = HIWORD(lParam);
    MoveToEx(hdc, 10, 10, NULL);
    LineTo(hdc, xPos, yPos);
    //还回去
    SelectObject(hdc, holdPen);
}
void DrawString(HDC hdc, const WCHAR *string, const Gdiplus::PointF &origin)
{
    Gdiplus::Graphics graphics(hdc);
    Gdiplus::FontFamily fontFamily(L"Times New Roman");
    Gdiplus::Font font(&fontFamily, 20, Gdiplus::FontStyle::FontStyleRegular, Gdiplus::Unit::UnitPixel);
    Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 0, 255));
    graphics.DrawString(string, -1, &font, origin, &solidBrush);
}
void DrawEllipse(HDC hdc)
{
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
    Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255));
    graphics.DrawEllipse(&pen, 1000, 10, 50, 50);

    DrawString(hdc, L"gdi+画圆抗锯齿", Gdiplus::PointF(10.0f, 10.0f));
}
void DrawRoundRect(Gdiplus::GraphicsPath &gp, float X, float Y, float width, float height, float radius)
{
    gp.AddLine(X + radius, Y, X + width - (radius * 2), Y);
    gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
    gp.AddLine(X + width, Y + radius, X + width, Y + height - (radius * 2));
    gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
    gp.AddLine(X + width - (radius * 2), Y + height, X + radius, Y + height);
    gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
    gp.AddLine(X, Y + height - (radius * 2), X, Y + radius);
    gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
    gp.CloseFigure();
}
VOID DrawTGdiplus(HDC hdc)
{
    //创建画板
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);

    //圆角矩形的线
    Gdiplus::GraphicsPath gp;
    DrawRoundRect(gp, 1000, 110, 100, 50, 10);

    //绘制线
    Gdiplus::Pen pen(Gdiplus::Color(255, 255, 0, 0), 1);
    graphics.DrawPath(&pen, &gp);
    Gdiplus::SolidBrush brush(Gdiplus::Color(255, 255, 255, 0));
    graphics.FillPath(&brush, &gp);

    DrawString(hdc, L"gdi+画圆角抗锯齿", Gdiplus::PointF(10.0f, 110.0f));
}
void DrawRoundedRect(HDC hdc)
{
    //创建画板
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
    Gdiplus::SolidBrush brush(Gdiplus::Color::Red);

    RECT rect = {1000, 220, 1100, 270};
    HRGN hRgn = CreateRectRgnIndirect(&rect);
    HRGN hRoundRgn = CreateRoundRectRgn(1000, 220, 1100, 270, 20, 20);
    // CombineRgn(hRgn, hRgn, hRoundRgn, RGN_AND);
    FillRgn(hdc, hRgn, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
    FillRgn(hdc, hRoundRgn, (HBRUSH)GetStockObject(LTGRAY_BRUSH));

    Gdiplus::Region rgn1(hRgn);
    Gdiplus::Region rgn2(hRoundRgn);
    rgn1.Intersect(&rgn2);
    graphics.FillRegion(&brush, &rgn1);

    DeleteObject(hRoundRgn);

    DrawString(hdc, L"gdi+区域合成圆角矩形不抗锯齿", Gdiplus::PointF(10.0f, 220.0f));
}
void DrawRegionRoundedRectGdiplus(HDC hdc)
{
    //创建画板
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);

    //圆角矩形的线
    Gdiplus::Rect rectf1 = {1000, 330, 100, 50};
    // Gdiplus::Rect rectf2 = {500, 50, 100, 50};

    // 画圆线 抗锯齿
    Gdiplus::GraphicsPath path1;
    DrawRoundRect(path1, 1000, 330, 50, 50, 10);
    Gdiplus::Pen pen(Gdiplus::Color::Red, 1);
    graphics.DrawPath(&pen, &path1);

    // 填充图 抗锯齿
    Gdiplus::GraphicsPath path2;
    DrawRoundRect(path2, 1100, 330, 50, 50, 10);
    Gdiplus::SolidBrush brush(Gdiplus::Color::Tomato);
    graphics.FillPath(&brush, &path2);

    // 填充图 不抗锯齿
    rectf1 = {1200, 330, 100, 50};
    Gdiplus::GraphicsPath path3;
    DrawRoundRect(path3, 1200, 330, 50, 50, 10);
    Gdiplus::Region reg1(rectf1);
    Gdiplus::Region reg2(&path3);
    reg1.Intersect(&reg2);
    graphics.FillRegion(&brush, &reg1);

    DrawString(hdc, L"gdi+区域合成圆角 圆线抗锯齿 填充抗锯齿 区域不抗锯齿", Gdiplus::PointF(10.0f, 330.0f));
}
void DrawRoundedRectGdi(HDC hdc)
{
    HPEN hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 255));
    HPEN holdPen = (HPEN)SelectObject(hdc, hPen);
    //画线
    RECT rect = {1000, 440, 1100, 500};
    HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 255));
    HBRUSH holdBrush = (HBRUSH)SelectObject(hdc, hBrush);
    FillRect(hdc, &rect, hBrush);
    RoundRect(hdc, 1000, 440, 1100, 500, 10, 10);
    //还回去
    SelectObject(hdc, holdPen);
    SelectObject(hdc, holdBrush);

    DrawString(hdc, L"gdi圆角矩形不抗锯齿", Gdiplus::PointF(10.0f, 440.0f));
}
void DrawRoundedRectGdiAndPlus(HDC hdc)
{
    //创建画板
    Gdiplus::Graphics graphics(hdc);
    graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
    //画线
    RECT rect = {1000, 550, 1100, 600};
    HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 255));
    HBRUSH holdBrush = (HBRUSH)SelectObject(hdc, hBrush);
    FillRect(hdc, &rect, hBrush);

    //借助border抗锯齿
    Gdiplus::GraphicsPath path;
    DrawRoundRect(path, 1000, 550, 100, 50, 10);
    Gdiplus::Pen pen(Gdiplus::Color::Red, 2);
    graphics.DrawPath(&pen, &path);

    //还回去
    SelectObject(hdc, holdBrush);

    DrawString(hdc, L"gdiAndGdi+区域混合借助border抗锯齿", Gdiplus::PointF(10.0f, 550.0f));
}
void DrawStretchBltGdiplus(HDC hdc)
{
    //创建画板
    HDC hMemdc = CreateCompatibleDC(hdc);
    HBITMAP hBmp = CreateCompatibleBitmap(hdc, 255, 255);
    HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemdc, hBmp);
    //在内存中绘图
    Gdiplus::Graphics graphics(hMemdc);
    Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 255, 255));
    graphics.FillRectangle(&solidBrush, 10, 10, 100, 50);
    //显示出来
    // BitBlt(hdc, 1000, 660, 150, 150, hMemdc, 0, 0, SRCCOPY);
    StretchBlt(hdc, 1000, 660, 150, 150, hMemdc, 0, 0, 255, 255, SRCCOPY);
    //删除
    graphics.ReleaseHDC(hMemdc); // 释放hMemhDc
    SelectObject(hMemdc, hOldBmp);
    DeleteObject(hBmp);
    DeleteDC(hMemdc);

    DrawString(hdc, L"gdi+内存图", Gdiplus::PointF(10.0f, 660.0f));
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    switch (uMsg)
    {
    case WM_CREATE:
    {
    }
    break;
    case WM_PAINT:
    {
        // HDC hdc = BeginPaint(hWnd, &ps);
        // HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
        // HPEN holdPen = (HPEN)SelectObject(hdc, hPen);

        // Ellipse(hdc, 10 + 25, 10, 60 + 25, 60);

        // SelectObject(hdc, holdPen);

        // DeleteObject(hPen);
        // EndPaint(hWnd, &ps);

        hdc = BeginPaint(hWnd, &ps);
        DrawRoundRectRgn(hdc);
        DrawLine(hdc);
        DrawEllipse(hdc);
        DrawTGdiplus(hdc);
        DrawRoundedRect(hdc);
        DrawRoundedRectGdi(hdc);
        DrawRegionRoundedRectGdiplus(hdc);
        DrawRoundedRectGdiAndPlus(hdc);
        DrawStretchBltGdiplus(hdc);
        EndPaint(hWnd, &ps);
    }
    break;
    case WM_SIZE:
    {
    }
    break;
    case WM_COMMAND:
    {
    }
    break;
    case WM_LBUTTONDOWN:
    {
        DrawLineMouse(hWnd, lParam);
    }
    break;
    case WM_RBUTTONDOWN:
    {
        InvalidateRect(hWnd, NULL, TRUE);
    }
    break;
    case WM_KEYDOWN:
    {
    }
    break;
    case WM_CLOSE:
    {
        DestroyWindow(hWnd);
    }
    break;
    case WM_DESTROY:
    {
        PostQuitMessage(0);
    }
    break;
    default:
    {
    }
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

// WINAPI代表__stdcall 参数的传递顺序 从右到左 依次入栈 并且在函数返回前 依次出栈
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS wc;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    // Initialize GDI+.
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    wc.cbClsExtra = 0;                                      // 类的额外内存
    wc.cbWndExtra = 0;                                      // 窗口额外内存
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 背景
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);               // 光标 第一个为NULL代表使用系统提供的光标
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);             // 图标 第一个为NULL代表使用系统提供的图标
    wc.hInstance = hInstance;                               // 应用程序实例句柄
    wc.lpfnWndProc = WindowProc;                            // 回调函数
    wc.lpszClassName = TEXT("main");                        // 窗口类名称
    wc.lpszMenuName = NULL;                                 // 菜单名称
    wc.style = CS_HREDRAW | CS_VREDRAW;                     // 显示风格

    RegisterClass(&wc);

    /*****
     * CreateWindow()
     * lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam
     * 类名
     * 标题名
     * WS_OVERLAPPEDWINDOW 混合风格
     * x坐标 CW_USEDEFAULT
     * y坐标
     * 宽
     * 高
     * 父窗口 NULL
     * 菜单 NULL
     * 实例句柄 hInstance
     * 附加值
     */
    HWND hWnd = CreateWindow(wc.lpszClassName, TEXT("Windows"), WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             NULL, NULL, hInstance, NULL);
    if (hWnd == NULL)
    {
        return 0;
    }
    ShowWindow(hWnd, SW_SHOWNORMAL);
    UpdateWindow(hWnd);

    /*****
     * HWND hwnd; 主窗口句柄
     * UINT message; 具体消息名称
     * WPARAM wParam; 附加消息 键盘消息
     * LPARAM lParam; 附加消息 鼠标消息
     * DWORD time; 消息产生时间
     * POINT pt; 附加消息 鼠标消息 x y
     */
    MSG msg;

    /*****
     * LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax
     * 消息
     * 捕获窗口 NULL代表捕获所有窗口
     * 最小的过滤消息 0代表捕获所有消息
     * 最大的过滤消息 0代表捕获所有消息
     */
    while (GetMessage(&msg, NULL, 0, 0))
    {
        // 如果按的是组合键 需要翻译
        TranslateMessage(&msg);
        // 单按一个键盘就直接分发消息
        DispatchMessage(&msg);
    }
    Gdiplus::GdiplusShutdown(gdiplusToken);
    return 0;
}